﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Xml.Linq;
using System.Windows;

namespace OpticalPowerMeter
{
    /// <summary>
    /// 用于保存及获取用户的最后配置信息,XML型式保存在本地Config目录
    /// </summary>
    public class CurrentConfigManagement
    {
        #region 单例模式
        static CurrentConfigManagement config = null;

        private CurrentConfigManagement() { }

        public static CurrentConfigManagement GetIntance()
        {
            if (config == null) { config = new CurrentConfigManagement(); }
            return config;
        }
        #endregion


        //配置文件保存的完整名称
        private string FileName = System.Environment.CurrentDirectory + "\\Config\\" + "LastConfig.xml";

        private void InitFile()
        {
            string path = System.Environment.CurrentDirectory + "\\Config";
            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }
            #region 如果文件不存在，添加文件
            if (!File.Exists(FileName))
            {
                XDocument xDoc = new XDocument(
                    new XDeclaration("1.0", "UTF-8", "yes"),
                    new XElement("LastOperate"));
                xDoc.Save(FileName);
            }
            #endregion
        }

        /// <summary>
        /// 保存选择的产品名称至本地
        /// </summary>
        /// <param name="productName">机型名称</param>
        public void SaveSeletProductName(string productName)
        {
            InitFile();
            XElement root = XElement.Load(FileName);
            var productNameResult = (from element in root.Elements("SelectProductName")
                                     select element);

            #region 如果没有选择型号配置，则添加该信息内容
            if (productNameResult.Count() == 0)
            {
                root.AddFirst(new XElement("SelectProductName", productName));
                root.Save(FileName);
                return;
            }
            #endregion

            #region 如果存在选择型号，则对比传入的值与本地内容，不一致的更新内容
            XElement productNameElement = productNameResult.SingleOrDefault();
            string localProductName = productNameElement.Value.Trim();
            if (productName != localProductName)
            {
                productNameElement.Value = productName;
                root.Save(FileName);
            }
            #endregion
        }

        /// <summary>
        /// 获取用户最后一次选中的机型名称
        /// </summary>
        /// <returns>机型名称</returns>
        public string GetSelectProductName()
        {
            if (!File.Exists(FileName))
            {
                return "";
            }

            XElement root = XElement.Load(FileName);
            var productNameResult = (from element in root.Elements("SelectProductName")
                                     select element);
            if (productNameResult.Count() == 0)
            {
                return "";
            }
            XElement productNameElement = productNameResult.SingleOrDefault();
            return productNameElement.Value.Trim();
        }

        /// <summary>
        /// 添加测试步骤,保存到本地配置文件中
        /// </summary>
        /// <param name="step">测试步骤、枚举TestSteps的一种</param>
        public void AddStep(TestSteps step)
        {
            InitFile();
            XElement root = XElement.Load(FileName);
            var testStepResult = (from element in root.Elements("TestSteps")
                                  select element);
            #region 如果不存在TestSteps节点，则添加该节点
            if (testStepResult.Count() == 0)
            {
                root.Add(new XElement("TestSteps", step.ToString()));
                root.Save(FileName);
                return;
            }
            #endregion
            XElement stepElement = testStepResult.SingleOrDefault();
            string stepString = stepElement.Value.ToString();
            #region 如果已存在相应节点，则退出
            if (stepString.Contains(step.ToString()))
            {
                return;
            }
            #endregion
            List<string> stepList = stepString.Split(',').ToList();
            stepList.Add(step.ToString());
            string steps = "";
            foreach (string s in stepList)
            {
                if (s != "")
                {
                    steps = s + "," + steps;
                }
            }
            stepElement.Value = steps;
            root.Save(FileName);
        }

        /// <summary>
        /// 从本地配置文件中去除测试步骤
        /// </summary>
        /// <param name="step">测试步骤、枚举TestSteps的一种</param>
        public void RemoveStep(TestSteps step)
        {
            if (!File.Exists(FileName))
            {
                return;
            }
            XElement root = XElement.Load(FileName);
            var testStepResult = (from element in root.Elements("TestSteps")
                                  select element);
            if (testStepResult.Count() == 0)
            {
                return;
            }
            XElement stepElement = testStepResult.SingleOrDefault();
            string stepString = stepElement.Value.ToString();
            #region 如果不存在相应节点，则退出
            if (!stepString.Contains(step.ToString()))
            {
                return;
            }
            #endregion
            List<string> stepList = stepString.Split(',').ToList();
            string steps = "";
            foreach (string s in stepList)
            {
                if (s != "" && s != step.ToString())
                {
                    steps = s + "," + steps;
                }
            }
            stepElement.Value = steps;
            root.Save(FileName);
        }


        /// <summary>
        /// 获取执行步骤清单
        /// </summary>
        /// <returns>返回执行步骤清单</returns>
        public List<TestSteps> GetStepList()
        {
            List<TestSteps> stepList = new List<TestSteps>();
            if (!File.Exists(FileName))
            {
                return stepList;
            }
            XElement root = XElement.Load(FileName);
            var testStepResult = (from element in root.Elements("TestSteps")
                                  select element);
            if (testStepResult.Count() == 0)
            {
                return stepList;
            }
            XElement stepElement = testStepResult.SingleOrDefault();
            string stepString = stepElement.Value.ToString();
            List<string> stepStringList = stepString.Split(',').ToList();
            foreach (string s in stepStringList)
            {
                switch (s)
                {
                    case "Linear":
                        stepList.Add(TestSteps.Linear);
                        break;
                    case "Correct":
                        stepList.Add(TestSteps.Correct);
                        break;
                    case "CheckValue":
                        stepList.Add(TestSteps.CheckValue);
                        break;
                }
            }
            return stepList;
        }


        /// <summary>
        /// 保存参考表的修正值至本地
        /// </summary>
        /// <param name="corrections">字典对象，Key - 波长 , 该波长下的修正点及修正值</param>
        public void SaveSampleMeterCorrection(Dictionary<string, List<SampleMeterCorrection>> corrections)
        {
            InitFile();
            XElement root = XElement.Load(FileName);
            XElement sampleMeterCorrectionElement = root.Element("SampleMeterCorrections");
            #region 如果不存在SampleMeterCorrection节点，则添加该节点
            if (sampleMeterCorrectionElement == null)
            {
                root.Add(new XElement("SampleMeterCorrections"));
                root.Save(FileName);
                sampleMeterCorrectionElement = root.Element("SampleMeterCorrections");
            }
            #endregion
            #region 写入传入参数每个波长的修正点节点
            foreach (string wavelength in corrections.Keys)
            {
                var resultWavelengthResult = (from element in sampleMeterCorrectionElement.Elements("SampleMeterCorrection")
                                              where element.Attribute("Wavelength") != null
                                              && element.Attribute("Wavelength").Value.Equals(wavelength)
                                              select element);
                if (resultWavelengthResult.Count() == 0)
                {
                    sampleMeterCorrectionElement.Add(new XElement("SampleMeterCorrection", new XAttribute("Wavelength", wavelength)));
                    root.Save(FileName);
                }
                #region 获取相应波长的节点
                XElement wavelengthElement = (from element in sampleMeterCorrectionElement.Elements("SampleMeterCorrection")
                                              where element.Attribute("Wavelength") != null
                                              && element.Attribute("Wavelength").Value.Equals(wavelength)
                                              select element).SingleOrDefault();
                #endregion
                #region 波长下的修正点清单,全部写入配置文件
                List<SampleMeterCorrection> correctionList = corrections[wavelength];
                foreach (SampleMeterCorrection correction in correctionList)
                {
                    WritedownCorrection(wavelengthElement, correction);
                }
                #endregion
            }
            #endregion

            #region 删除本地存在、传入参数中不存在的点
            Dictionary<string, List<SampleMeterCorrection>> localCorrectionDic = GetLocalCorrecntion(); //获取本地校准点
            foreach (string wavelength in localCorrectionDic.Keys)
            {
                #region 如果本地波长不在传入参数之中，直接删除该波长节点
                if (!corrections.Keys.Contains(wavelength))
                {
                    XElement resultWavelengthResult = (from element in sampleMeterCorrectionElement.Elements("SampleMeterCorrection")
                                                       where element.Attribute("Wavelength") != null
                                                       && element.Attribute("Wavelength").Value.Equals(wavelength)
                                                       select element).SingleOrDefault();
                    resultWavelengthResult.Remove();
                    root.Save(FileName);
                    continue;
                }
                #endregion
                #region 对比本地波长下对应的校准点，如果传入的校准点中不存则删除该校准点
                //本地校准点清单
                List<SampleMeterCorrection> localSampleMeterCorrection = localCorrectionDic[wavelength];
                List<string> localCorrectionPointList = new List<string>();
                foreach (SampleMeterCorrection sampleMeter in localSampleMeterCorrection)
                {
                    localCorrectionPointList.Add(sampleMeter.CorrectPoint);
                }
                //传入参数校准清单
                List<SampleMeterCorrection> paramSampleMeterCorrection = corrections[wavelength];
                List<string> paramCorrectionPointList = new List<string>();
                foreach (SampleMeterCorrection sampleMeter in paramSampleMeterCorrection)
                {
                    paramCorrectionPointList.Add(sampleMeter.CorrectPoint);
                }
                foreach (string correctionPoint in localCorrectionPointList)
                {
                    if (!paramCorrectionPointList.Contains(correctionPoint))
                    {
                        XElement wavelengthElement = (from element in sampleMeterCorrectionElement.Elements("SampleMeterCorrection")
                                                      where element.Attribute("Wavelength") != null
                                                      && element.Attribute("Wavelength").Value.Equals(wavelength)
                                                      select element).SingleOrDefault();
                        XElement correctionElement = (from element in wavelengthElement.Elements("Correction")
                                                      where element.Attribute("Point") != null
                                                      && element.Attribute("Point").Value.Equals(correctionPoint)
                                                      select element).SingleOrDefault();
                        correctionElement.Remove();
                        root.Save(FileName);
                    }
                }
                #endregion
            }
            #endregion
        }

        /// <summary>
        /// 获取参考表修正值清单
        /// </summary>
        /// <returns>字典对象，Key - 波长 , 该波长下的修正点及修正值</returns>
        public Dictionary<string, List<SampleMeterCorrection>> GetLocalCorrecntion()
        {
            //key - 波长 Value - 校准点清单
            Dictionary<string, List<SampleMeterCorrection>> correctionDic = new Dictionary<string, List<SampleMeterCorrection>>();
            if (!File.Exists(FileName))
            {
                return correctionDic;
            }
            XElement root = XElement.Load(FileName);
            var sampleMeterCorrectionResult = root.Elements("SampleMeterCorrections");
            if (sampleMeterCorrectionResult.Count() == 0)
            {
                return correctionDic;
            }
            #region 遍历所有的节点,并返回节点对应的清单数据
            XElement sampleMeterCorrectionElement = sampleMeterCorrectionResult.SingleOrDefault();
            foreach (XElement wavlengthElement in sampleMeterCorrectionElement.Elements("SampleMeterCorrection"))
            {
                string wavlength = wavlengthElement.Attribute("Wavelength").Value;
                List<SampleMeterCorrection> correctionList = GetCorrectionPointList(wavlengthElement);
                correctionDic.Add(wavlength, correctionList);
            }
            return correctionDic;
            #endregion
        }


        //获取指定节点下的修正点清单
        private List<SampleMeterCorrection> GetCorrectionPointList(XElement parentElement)
        {
            List<SampleMeterCorrection> correctionPointList = new List<SampleMeterCorrection>();
            var corretionPointResult = parentElement.Elements("Correction");
            if (corretionPointResult.Count() == 0)
            {
                return correctionPointList;
            }
            foreach (XElement correctionPointElement in corretionPointResult)
            {
                string correctionPoint = correctionPointElement.Attribute("Point").Value;
                string correctionValue = correctionPointElement.Value;
                SampleMeterCorrection correction = new SampleMeterCorrection();
                correction.CorrectPoint = correctionPoint;
                correction.CorrectValue = correctionValue;
                correctionPointList.Add(correction);
            }
            return correctionPointList;
        }


        //写入修正点
        private void WritedownCorrection(XElement parentElement, SampleMeterCorrection correction)
        {
            string correctionPoint = correction.CorrectPoint;
            string correctionValue = correction.CorrectValue;
            var correctionResult = (from element in parentElement.Elements("Correction")
                                    where element.Attribute("Point") != null
                                    && element.Attribute("Point").Value.Equals(correctionPoint)
                                    select element);
            if (correctionResult.Count() == 0)
            {
                parentElement.Add(new XElement("Correction", new XAttribute("Point", correctionPoint), correctionValue)); //添加节点值到对应波长的节点下
                parentElement.Parent.Parent.Save(FileName);
                return;
            }
            #region 对比已经存在的节点值是否与传入值一致,如果不一致则更新数据
            XElement correctionElement = correctionResult.SingleOrDefault();
            string localCorrection = correctionElement.Value.ToString();
            if (!localCorrection.Equals(correctionValue))
            {
                correctionElement.Value = correctionValue;
                parentElement.Parent.Parent.Save(FileName);
            }
            #endregion
        }


        /// <summary>
        /// 保存主界面尺寸到本地
        /// </summary>
        /// <param name="size">主界面尺寸</param>
        public void SaveMainWindowSize(Size size) {
            InitFile();
            string mainNodeName = "MainWindowSize";
            string heightNodeName = "Height";
            string widthNodeName = "Width";
            double width = size.Width;
            double height = size.Height;
            XElement root = XElement.Load(FileName);
            XElement mainWindowSizeElement = root.Element(mainNodeName);
            #region 如果不存在MainWindowSize节点，直接添加该节点
            if (mainWindowSizeElement == null)
            {
                root.Add(new XElement(mainNodeName, new XAttribute(heightNodeName, height), new XAttribute(widthNodeName, width)));
                root.Save(FileName);
                return;
            }
            #endregion
            #region 刷新节点属性
            double localHeight = Convert.ToDouble(mainWindowSizeElement.Attribute(heightNodeName).Value);
            double localWidth = Convert.ToDouble(mainWindowSizeElement.Attribute(widthNodeName).Value);
            if (localHeight != height || localWidth != width) //传入的尺寸与本地尺寸不一致时，保存新的值
            {
                mainWindowSizeElement.Attribute(heightNodeName).Value = height.ToString();
                mainWindowSizeElement.Attribute(widthNodeName).Value = width.ToString();
                root.Save(FileName);
            }
            #endregion
        }


        /// <summary>
        /// 获取本地配置文件中的主框架尺寸，无相应的本地配置文件时，返回-1,-1
        /// </summary>
        /// <returns></returns>
        public Size GetMainWindowSize()
        {
            InitFile();
            string mainNodeName = "MainWindowSize";
            string heightNodeName = "Height";
            string widthNodeName = "Width";
            XElement root = XElement.Load(FileName);
            XElement mainWindowSizeElement = root.Element(mainNodeName);
            #region 如果不存在MainWindowSize节点，返回两个-1
            if (mainWindowSizeElement == null)
            {
                return new Size(-1,-1);
            }
            #endregion
            #region 返回本地配置的宽度、高度
            double localHeight = Convert.ToDouble(mainWindowSizeElement.Attribute(heightNodeName).Value);
            double localWidth = Convert.ToDouble(mainWindowSizeElement.Attribute(widthNodeName).Value);
            return new Size(localWidth,localHeight);
            #endregion
        }
    }
}
